﻿using System;
using System.Threading;
using System.Threading.Tasks;
using MediatR;
using Casamiel.Application;
using Enyim.Caching;
using Microsoft.Extensions.Options;
using Casamiel.Common;
using Casamiel.Domain.Entity;
using Casamiel.Common.Extensions;
using System.Linq;

namespace Casamiel.API.Application.Commands
{
    /// <summary>
    /// 
    /// </summary>
    public class UpdateStockV1CommandHandler : INotificationHandler<UpdateStockCommand>
    {
        private readonly IStoreService _storeService;
        private readonly IProductService _product;
        private readonly IMemcachedClient _memcachedClient;
        private readonly string _memcachedPre = "";
        private readonly NLog.ILogger _stocklogger = NLog.LogManager.GetLogger("StockService");
        /// <summary>
        /// Initializes a new instance of the
        /// 
        /// </summary>
        /// <param name="product"></param>
        /// <param name="snapshot">Snapshot.</param>
        /// <param name="storeService">Store service.</param>
        /// <param name="memcachedClient">Memcached client.</param>
        public UpdateStockV1CommandHandler(IProductService product, IOptionsSnapshot<CasamielSettings> snapshot, IStoreService storeService, IMemcachedClient memcachedClient)
        {
            if (snapshot == null) {
                throw new ArgumentNullException(nameof(snapshot));
            }

            _storeService = storeService;
            _memcachedClient = memcachedClient;
            _memcachedPre = snapshot.Value.MemcachedPre;
            _product = product;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="notification"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task Handle(UpdateStockCommand notification, CancellationToken cancellationToken)
        {
            if (notification == null) {
                throw new ArgumentNullException(nameof(notification));
            }

            try {
                if (notification.StockPush == null || notification.StockPush.Productstock.Count == 0) {
                    await Task.FromResult(true).ConfigureAwait(false);
                }
                int count = notification.StockPush.Productstock.Count;

                for (int i = 0; i < count; i++) {
                    var item = notification.StockPush.Productstock[i];
                    var _cacheKey = _memcachedPre + Constant.SHOPRELATIONID + item.Shopid;
                    // _stocklogger.Trace($"cacheey:{_cacheKey}");
                    var storeidResult = await _memcachedClient.GetAsync<int>(_cacheKey).ConfigureAwait(false);
                    var storeId = 0;
                    if (!storeidResult.Success) {
                        var entity = await _storeService.GetByRelationIdAsync<ICasaMielSession>(item.Shopid).ConfigureAwait(false);
                        if (entity != null) {
                            await _memcachedClient.AddAsync(_cacheKey, entity.StoreId, 72000).ConfigureAwait(false);
                            storeId = entity.StoreId;
                        } else {
                            await _memcachedClient.AddAsync(_cacheKey, 0, 72000).ConfigureAwait(false);
                        }
                    } else {
                        storeId = storeidResult.Value;
                    }
                    if (storeId > 0) {
                        if (item.Product != null) {
                            var p_count = item.Product.Count;
                            for (int n = 0; n < p_count; n++) {
                                await _product.UpdateStockAsync<ICasaMielSession>(storeId, item.Product[n].pid.ToInt32(0), item.Product[n].count).ConfigureAwait(false);
                            }
                        }

                    }

                }
                await Task.FromResult(true).ConfigureAwait(false );
            } catch (AggregateException ex) {
                foreach (var item in ex.InnerExceptions) {
                    _stocklogger.Error(item.StackTrace);
                }
                _stocklogger.Error($"UpdateStockV1Async;{ex.Message}");
                await Task.FromResult(true).ConfigureAwait(false);
            }
        }
    }

    /// <summary>
    /// Update stock command handler.
    /// </summary>
    public class UpdateStockCommandHandler : INotificationHandler<UpdateStockCommand>
    {
        private readonly IStoreService _storeService;
        private readonly IProductService _product;
        private readonly IMemcachedClient _memcachedClient;
        private readonly string _memcachedPre = "";
        private readonly NLog.ILogger _stocklogger = NLog.LogManager.GetLogger("StockService");
        /// <summary>
        /// Initializes a new instance of the
        /// 
        /// </summary>
        /// <param name="product"></param>
        /// <param name="snapshot">Snapshot.</param>
        /// <param name="storeService">Store service.</param>
        /// <param name="memcachedClient">Memcached client.</param>
        public UpdateStockCommandHandler(IProductService product, IOptionsSnapshot<CasamielSettings> snapshot, IStoreService storeService, IMemcachedClient memcachedClient)
        {
            if (snapshot == null) {
                throw new ArgumentNullException(nameof(snapshot));
            }

            _storeService = storeService;
            _memcachedClient = memcachedClient;
            _memcachedPre = snapshot.Value.MemcachedPre;
            _product = product;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns>The handle.</returns>
        /// <param name="notification">Request.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        public async Task Handle(UpdateStockCommand notification, CancellationToken cancellationToken)
        {
            if (notification == null) {
                throw new ArgumentNullException(nameof(notification));
            }

            try {
                if (notification.StockPush == null || notification.StockPush.Productstock.Count == 0) {
                    await Task.FromResult(true).ConfigureAwait(false );
                }
                int count = notification.StockPush.Productstock.Count;

                for (int i = 0; i < count; i++) {
                    var item = notification.StockPush.Productstock[i];
                    var _cacheKey = _memcachedPre + Constant.SHOPRELATIONID + item.Shopid;
                    // _stocklogger.Trace($"cacheey:{_cacheKey}");
                    var storeidResult = await _memcachedClient.GetAsync<int>(_cacheKey).ConfigureAwait(false);
                    var storeId = 0;
                    if (!storeidResult.Success) {
                        var entity = await _storeService.GetByRelationIdAsync<ICasaMielSession>(item.Shopid).ConfigureAwait(false);
                        if (entity != null) {
                            await _memcachedClient.AddAsync(_cacheKey, entity.StoreId, 72000).ConfigureAwait(false);
                            storeId = entity.StoreId;
                        } else {
                            await _memcachedClient.AddAsync(_cacheKey, 0, 72000).ConfigureAwait(false);
                        }
                    } else {
                        storeId = storeidResult.Value;
                    }
                    if (storeId > 0) {
                        if (item.Product != null) {
                            var p_count = item.Product.Count;
                            for (int n = 0; n < p_count; n++) {
                                await _product.UpdateStockV2Async<ICasaMielSession>(storeId, item.Product[n].pid.ToInt32(0), item.Product[n].count).ConfigureAwait(false);
                            }
                        }

                    }

                }
                await Task.FromResult(true).ConfigureAwait(false);
            } catch (AggregateException ex) {
                foreach (var item in ex.InnerExceptions) {
                    _stocklogger.Error(item.StackTrace);
                }
                _stocklogger.Error($"UpdateStockV2Async;{ex.Message}");
                await Task.FromResult(true).ConfigureAwait(false);
            }

        }

    }
}
